#!/bin/bash
#
# Copyright 2015-2017 Adrian DC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# === Megatools Mirror ===
function megamirror()
{
  # Usage
  if [ -z "${1}" ] || [ -z "${2}" ] || [ -z "${3}" ]; then
    echo '';
    echo ' Usage: megamirror <local_folder> <remote_folder> <--upload/--download> [--copy,-y/-n] (MEGA mirror syncer)';
    echo '';
    echo '  > Upload with --upload (individual), optional --copy (megacopy)';
    echo '  > Download with --download (individual), optional --copy (megacopy)';
    echo '';
    return;
  fi;

  # Verify megatools is installed
  if ! type megals >/dev/null 2>&1; then
    echo '';
    echo ' megatools: Please install megatools before using tools like "megals"';
    echo '';
    return;
  fi;

  # Ignore missing credentials
  if [ ! -f "${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" ]; then
    echo '';
    echo " megatools: ${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc is missing, please read megatools documentation";
    echo '';
    return;
  fi;

  # Variables
  local local_folder=${1};
  local remote_folder=${2%/};
  local option_direction=${3};
  local option_params=${4};
  local tmp_local_ls;
  local tmp_remote_ls;
  local flag_delete;
  local key;
  local key_override;
  local line;
  local line_tmp;
  local file_type;
  local file_size;
  local file_path;
  local file_local;
  local file_escaped;
  local file_local_output;
  local file_local_size;
  local time_start;
  local time_span;

  # Initialize variables
  tmp_local_ls=$(mktemp);
  tmp_remote_ls=$(mktemp);

  # =======================================================
  # Parameters input
  if [[ "${option_params}" == *'-y'* ]]; then
    key_override=true;
    key=y;
  elif [[ "${option_params}" == *'-n'* ]]; then
    key_override=true;
    key=n;
  else
    key_override=;
  fi;

  # =======================================================
  # Introduction message
  echo '';
  echo -e " \e[1;37mmegamirror: Syncing '${local_folder}' and '${remote_folder}'...\e[0m";

  # Remove local megatools cache
  rm -rf /tmp/*.megatools.cache;

  # Retrieve files informations
  find "${local_folder}" -mindepth 1 -printf '%s\t%P#\n' > "${tmp_local_ls}";
  megals --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
      -lR "${remote_folder}" > "${tmp_remote_ls}";

  # =======================================================
  # Upload mode
  if [ ! "${option_direction}" = '--download' ]; then

    # Parse all remote files
    while [ -s "${tmp_remote_ls}" ]; do

      # Extract first line
      IFS=' ' read -r -a line <<< "$(sed '1!d' "${tmp_remote_ls}")";
      sed -i '1d' "${tmp_remote_ls}";

      # Ignore empty lines
      if [ -z "${line[*]}" ]; then
        continue;
      fi;

      # Parse line content
      file_type=${line[2]};
      file_size=${line[3]};
      file_path=${line[*]:6};
      file_local=${file_path#${remote_folder}};
      file_local=${file_local#/};
      file_local_output=${file_local//\\/\\\\};
      file_escaped=${file_local_output//\|/\\\|};
      file_escaped=${file_escaped//\[/\\\[};
      file_escaped=${file_escaped//\]/\\\]};
      flag_delete=;

      # Ignore irrelevant paths
      if [ "${file_path}" = "${remote_folder}" ]; then
        continue;
      fi;

      # Verify folder exists
      if [ "${file_type}" = '1' ] && [ "${file_size}" = '-' ]; then
        if [ ! -d "${file_local}" ]; then
          echo -en " \e[1;31mmegamirror: Remote folder '${file_local_output}/' is missing:\e[0m";
          flag_delete=true;

        # Exclude folder from needed uploads
        else
          sed -i "\|\t${file_escaped}#|d" "${tmp_local_ls}";
        fi;

      # Verify files sizes do not mismatch
      elif [ -f "${file_local}" ]; then
        file_local_size=$(stat -c "%s" "${file_local}");
        if [ "${file_size/-/0}" -ne "${file_local_size}" ]; then
          echo -en " \e[1;31mmegamirror: Remote file '${file_local_output}' is different:\e[0m";
          flag_delete=true;

        # Exclude file from needed uploads
        else
          sed -i "\|\t${file_escaped}#|d" "${tmp_local_ls}";
        fi;

      # Remote file no longer exist locally
      else
        echo -en " \e[1;31mmegamirror: Remote file '${file_local_output}' locally removed:\e[0m";
        flag_delete=true;
      fi;

      # Delete remote file
      if [ ! -z "${flag_delete}" ]; then
        echo -n ' Delete remote [y/N] ? ';
        if [ -z "${key_override}" ]; then
          if ! read -r -t 20 key; then
            echo '';
          fi;
        else
          echo '';
        fi;
        if [ "${key}" = 'Y' ] || [ "${key}" = 'y' ]; then
          megarm --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
              "${file_path}";
          echo -e " \e[1;32mmegamirror: Removed remote '${file_path}'\e[0m";

          # Remove folder elements
          if [ "${file_type}" = '1' ]; then
            sed -i "\|${file_escaped}|d" "${tmp_remote_ls}";
          fi;
        fi;
      fi;

    done;

    # ===========================================
    # Upload with megacopy to remote
    if [[ "${option_params}" == *'--copy'* ]]; then
      echo -e " \e[1;33mmegamirror: megacopy starting...\e[0m";
      rm -rf /tmp/*.megatools.cache;
      megacopy --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
          --local "${local_folder}" --remote "${remote_folder}" 2>&1 \
        | grep -v 'ERROR: File already exists at';

    # Upload with megaput to remote
    else

      # Check all files listed for upload
      while [ -s "${tmp_local_ls}" ]; do
        IFS=$'\t' read -r -a line <<< "$(sed '1!d' "${tmp_local_ls}")";
        sed -i '1d' "${tmp_local_ls}";

        # Parse file informations
        file_local=${line[*]:1};
        file_local=${file_local#/};
        file_local=${file_local%#};
        file_path=${remote_folder}/${file_local};
        time_start=$(date +%s);

        # Create remote folder
        if [ -d "${file_local}" ]; then
          megamkdir --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
              "${file_path}";
          echo -e " \e[1;33mmegamirror: Created remote folder '${file_path}/'\e[0m";

        # Upload file to target
        else
          file_path=$(dirname "${file_path}");
          echo -e " \e[1;33mmegamirror: Uploading to the server - Path '${file_path}'\e[0m";
          megamkdir --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
              "${file_path}" 2>&1 \
            | grep -v 'Directory already exists:';
          megaput --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
              --path "${file_path}" "${file_local}";

          # Show upload time
          time_span=$(($(date +%s) - time_start));
          echo -e " \e[1;37mmegamirror: Upload done in ${time_span} secs\e[0m";

        fi;
      done;
    fi;

  # =======================================================
  # Download mode
  else

    # Parse all local files
    while [ -s "${tmp_local_ls}" ]; do

      # Extract first line
      IFS=$'\t' read -r -a line <<< "$(sed '1!d' "${tmp_local_ls}")";
      sed -i '1d' "${tmp_local_ls}";

      # Ignore empty lines
      if [ -z "${line[*]}" ]; then
        continue;
      fi;

      # Parse line content
      file_size=${line[0]};
      file_path=${line[*]:1};
      file_path=${file_path%#};
      file_local=${file_path#${local_folder}};
      file_local=${file_local#/};
      file_local_output=${file_local//\\/\\\\};
      file_escaped=${file_path//\\/\\\\};
      file_escaped=${file_escaped//\|/\\\|};
      file_escaped=${file_escaped//\[/\\\[};
      file_escaped=${file_escaped//\]/\\\]};
      flag_delete=;

      # Ignore irrelevant paths
      if [ "${file_path}" = '' ] || [ ! -e "${file_path}" ]; then
        continue;
      fi;

      # Extract remote information
      file_type=0;
      if [ -d "${file_path}" ]; then
        file_type=1;
      fi;
      IFS=' ' read -r -a line_tmp <<< "$(awk "\$3 == ${file_type}" "${tmp_remote_ls}" 2>&1 | grep "${remote_folder}/${file_escaped//\\\|/\|}$")";

      # Verify folder exists
      if [ -d "${file_path}" ]; then
        if [ -z "${line_tmp[2]}" ]; then
          echo -en " \e[1;31mmegamirror: Remote folder '${file_local_output}/' is missing:\e[0m";
          flag_delete=true;

        # Exclude folder from needed downloads
        else
          sed -i "\|${remote_folder}/${file_escaped}$|d" "${tmp_remote_ls}";
        fi;

      # Verify files sizes do not mismatch
      elif [ ! -z "${line_tmp[*]}" ]; then
        if [ "${file_size}" -ne "${line_tmp[3]/-/0}" ]; then
          echo -en " \e[1;31mmegamirror: Local file '${file_local_output}' is different:\e[0m";
          flag_delete=true;

        # Exclude file from needed downloads
        else
          sed -i "\|${remote_folder}/${file_escaped}$|d" "${tmp_remote_ls}";
        fi;

      # Local file no longer exist remotely
      else
        echo -en " \e[1;31mmegamirror: Local file '${file_local_output}' remotely removed:\e[0m";
        flag_delete=true;
      fi;

      # Delete local file
      if [ ! -z "${flag_delete}" ]; then
        echo -n ' Delete local [y/N] ? ';
        if [ -z "${key_override}" ]; then
          if ! read -r -t 20 key; then
            echo '';
          fi;
        else
          echo '';
        fi;
        if [ "${key}" = 'Y' ] || [ "${key}" = 'y' ]; then
          rm -r "${file_path}";
          echo -e " \e[1;32mmegamirror: Removed local '${file_path}'\e[0m";
        fi;
      fi;

    done;

    # ===========================================
    # Download with megacopy to local
    if [[ "${option_params}" == *'--copy'* ]]; then
      echo -e " \e[1;33mmegamirror: megacopy starting...\e[0m";
      rm -rf /tmp/*.megatools.cache;
      megacopy --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
          --local "${local_folder}" --remote "${remote_folder}" --download 2>&1 \
        | grep -v 'ERROR: File already exists at';

    # Download with megaget to local
    else

      # Check all files listed for upload
      while [ -s "${tmp_remote_ls}" ]; do
        IFS=' ' read -r -a line <<< "$(sed '1!d' "${tmp_remote_ls}")";
        sed -i '1d' "${tmp_remote_ls}";

        # Parse file informations
        file_type=${line[2]};
        file_path=${line[*]:6};
        file_local=${file_path#${remote_folder}};
        file_local=${file_local#/};
        file_escaped=${file_local//\|/\\\|};
        file_escaped=${file_escaped//\[/\\\[};
        file_escaped=${file_escaped//\]/\\\]};
        time_start=$(date +%s);

        # Ignore irrelevant paths
        if [ -z "${file_local}" ]; then
          continue;
        fi;

        # Create local folder
        if [ "${file_type}" = '1' ]; then
          if [ ! -d "${file_local}" ]; then
            mkdir -p "${file_local}";
            echo -e " \e[1;33mmegamirror: Created local folder '${file_local}/'\e[0m";
          fi;

        # Download file
        else

          # Download header informations
          file_local=$(dirname "${file_local}");
          echo -e " \e[1;33mmegamirror: Downloading from the server - Path '${file_local}/'\e[0m";

          # Download file to local
          mkdir -p "${file_local}";
          megaget --config="${ANDROID_DEVELOPMENT_SHELL_TOOLS_WORKSPACE:-${HOME}}/.megarc" \
              --path "${file_local}" "${file_path}";

          # Show download time
          time_span=$(($(date +%s) - time_start));
          echo -e " \e[1;37mmegamirror: Download done in ${time_span} secs\e[0m";

        fi;
      done;
    fi;
  fi;

  # =======================================================
  # End message
  echo -e " \e[1;32mmegamirror: Synced '${local_folder}' and '${remote_folder}'\e[0m";
  echo '';

  # Cleanup temp files
  rm "${tmp_local_ls}";
  rm "${tmp_remote_ls}";
}
